home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
QRZ! Ham Radio 8
/
QRZ Ham Radio Callsign Database - Volume 8.iso
/
pc
/
files
/
t_sys5
/
unixkit.tgz
/
unixkit.tar
/
unixkit
/
common
/
bsd_nit.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-11-20
|
9KB
|
322 lines
/* This is a very early release of a NIT driver for 4.3 BSD systems.
* You need to run this program as root. Please think about security
* during shell escapes, ftp-sessions etc.
* Define PACKET in config.h to use this driver.
*
* SM0RGV
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/param.h>
#include <sys/stropts.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <net/nit.h>
#include <net/nit_if.h>
#include <net/nit_pf.h>
#include <net/packetfilt.h>
#include "global.h"
#include "config.h"
#include "enet.h"
#include "mbuf.h"
#include "iface.h"
#include "arp.h"
#include "netuser.h"
#include "pktdrvr.h"
#include "asy.h"
struct nitdrvr Nitdrvr[NIT_MAX];
int nit_raw(),nit_stop();
void nit_input();
extern struct iface *Ifaces;
extern struct mbuf *Hopper;
extern char Nospace[];
int Nnit;
/* Define some TUN stuff to keep the compiler happy */
struct tundrvr Tundrvr[TUN_MAX];
int Ntun;
/* Attach a packet driver to the system
* argv[0]: hardware type, must be "packet"
* argv[1]: optional ethernet address or 0 for automatic assignment
* argv[2]: interface label, same as real interface, e.g., "le0"
* argv[3]: unused
* argv[4]: maximum transmission unit, bytes, e.g., "8192"
* argv[5]: optional IP address
*/
pk_attach(argc,argv,p)
int argc;
char **argv;
void *p;
{
struct strioctl si;
struct ifreq ifr;
struct timeval timeout;
struct iface *if_nit;
struct nitdrvr *pp;
struct packetfilt filt;
u_short *fwp;
int i,if_flags;
char addr[EADDR_LEN+1], hostn[MAXHOSTNAMELEN];
if(Nnit >= NIT_MAX){
tprintf("Too many nit drivers\n");
return -1;
}
if(if_lookup(argv[2]) != NULLIF){
tprintf("Interface %s already exists\n",argv[2]);
return -1;
}
if((if_nit = (struct iface *)calloc(1,sizeof(struct iface))) == NULLIF
||(if_nit->name = strdup(argv[2])) == NULLCHAR){
if(if_nit != NULLIF)
free((char *)if_nit);
tprintf(Nospace);
return -1;
}
if_nit->addr = Ip_addr;
if(argc > 5)
if_nit->addr = resolve(argv[5]);
if(if_nit->addr == 0){
tprintf(Noipaddr);
free((char *)if_nit);
return -1;
}
pp = &Nitdrvr[Nnit];
if_nit->mtu = atoi(argv[4]);
if_nit->dev = Nnit;
if_nit->raw = nit_raw;
if_nit->stop = nit_stop;
pp->iface = if_nit;
if_nit->send = enet_send;
if_nit->output = enet_output;
if_nit->type = CL_ETHERNET;
if((pp->IOser = open("/dev/nit", O_RDWR)) == -1) {
tprintf("Can't open /dev/nit\n");
free((char *)if_nit);
return -1;
}
/* Arrange to get discrete messages from the stream. */
ioctl(pp->IOser, I_SRDOPT, (char *)RMSGD);
/* Push the packet filtering module. It will be configured later */
ioctl(pp->IOser, I_PUSH, "pf");
/* Configure the nit device, binding it to the proper
underlying interface, and setting nit_if-level flags. */
strncpy(ifr.ifr_name, argv[2], sizeof ifr.ifr_name);
si.ic_timout = INFTIM;
si.ic_cmd = NIOCBIND;
si.ic_len = sizeof ifr;
si.ic_dp = (char *)𝔦
i = ioctl(pp->IOser, I_STR, (char *)&si);
if (i == -1) {
perror("ioctl bind");
free((char *)if_nit);
close (pp->IOser);
return -1;
}
/* Set promiscious mode, ie receive everything */
if_flags = NI_PROMISC;
si.ic_cmd = NIOCSFLAGS;
si.ic_len = sizeof if_flags;
si.ic_dp = (char *)&if_flags;
if (ioctl(pp->IOser, I_STR, (char *)&si) == -1) {
perror("ioctl");
free((char *)if_nit);
close(pp->IOser);
return -1;
}
/* Get hardware Ethernet address from driver */
ioctl(pp->IOser,SIOCGIFADDR,&ifr);
if (strcmp(argv[1],"0") == 0) {
/* Create our own Ethernet address! */
ifr.ifr_addr.sa_data[0] <<= 1;
/* Check if it is unique */
i = ether_ntohost(hostn,(struct ether_addr *)ifr.ifr_addr.sa_data);
if (i && hostn[0] != '\0' && strcmp(hostn,Hostname)){
tprintf("Bad luck, could not use my Ethernet address.\n");
free((char *)if_nit);
close(pp->IOser);
return -1;
}
}
/* Use the user supplied ethernet address */
else gether(ifr.ifr_addr.sa_data,argv[1]);
if((if_nit->hwaddr = malloc(EADDR_LEN)) == NULLCHAR){
free(if_nit->name);
free((char *)if_nit);
close(pp->IOser);
tprintf(Nospace);
return -1;
}
memcpy(if_nit->hwaddr,ifr.ifr_addr.sa_data,EADDR_LEN);
/* Now try to configure the packet filter.
The filter should eliminate all packets except broadcast
packets and those directed to us. This is not very easily
done however. The following will stop most unwanted packets,
but not all.
*/
fwp = filt.Pf_Filter;
for (i=0; i<EADDR_LEN; i += 2) { /* EADDR_LEN == 6 */
/* Check for own address */
*fwp++ = ENF_PUSHWORD + i/2;
*fwp++ = ENF_PUSHLIT | ENF_EQ;
/* *fwp++ = ENF_PUSHLIT | ENF_CAND;*/
*fwp++ = *((u_short *) &if_nit->hwaddr[i]);
/* Check for broadcast address */
*fwp++ = ENF_PUSHWORD + i/2;
*fwp++ = ENF_PUSHLIT | ENF_EQ;
*fwp++ = *((u_short *) &Ether_bdcst[i]);
*fwp++ = ENF_CNOR;
}
filt.Pf_FilterLen = fwp - &filt.Pf_Filter[0];
i = ioctl(pp->IOser,NIOCSETF,&filt);
if (i == -1){ perror("ioctl pf"); return -1;}
/* This didn't filter out all unwanted addresses however! */
/* Flush the read queue, to get rid of anything that accumulated
before the device reached its final configuration. */
ioctl(pp->IOser, I_FLUSH, (char *)FLUSHR);
if ((pp->buffer = malloc(pp->iface->mtu)) == NULLCHAR) {
tprintf("Can't allocate buffer\n");
free(if_nit->name);
free((char *)if_nit);
close(pp->IOser);
return -1;
}
/* Enable interrupt for input to an empty queue */
ioctl(pp->IOser,I_SETSIG,S_INPUT|S_HIPRI|S_MSG);
if_nit->next = Ifaces;
Ifaces = if_nit;
newproc("ether_rx",2048,nit_input,0,pp,NULL,0);
pether(addr,if_nit->hwaddr);
tprintf("Attached %s (%s)\n",ifr.ifr_name,addr);
++Nnit;
return 0;
}
/* This is the task that takes care of incoming ethernet packets.
It would be better to do all this at interrupt level (ie from inpint)
but the program seems to crash if you do memory allocation operations
from interrupt level without using alloc.c
*/
void nit_input(unused,pp,unused2)
struct nitdrvr *pp;
void *unused2;
{
int res,flags;
char i_state;
struct strbuf data, proto;
struct mbuf *bp;
struct phdr *phdr;
fd_set readfds;
struct timeval timeout;
FD_ZERO (&readfds);
timeout.tv_sec = 0;
timeout.tv_usec = 35;
proto.buf = malloc(ETHERLEN);
proto.maxlen = ETHERLEN;
proto.len = 0;
data.buf = pp->buffer;
data.maxlen = pp->iface->mtu;
data.len = 0;
for (;;) {
/* If there are no new messages to fetch from the NIT interface,
* then wait until inpint() gives you a signal.
*/
i_state = dirps();
while (FD_SET(pp->IOser,&readfds), select(NOFILE,
&readfds,(fd_set *)0,(fd_set *)0,&timeout) <= 0)
pwait(pp);
restore(i_state);
flags = 0;
res = getmsg(pp->IOser,&proto,&data,&flags);
if (res == -1)
perror("getmsg");
/* Process the packet.
/* Since I didn't manage to make the filter inhibit all unwanted
packets we must check the destination address one more time */
if (memcmp(pp->iface->hwaddr,data.buf,EADDR_LEN)
&& memcmp(Ether_bdcst,data.buf,EADDR_LEN))
continue;
if((bp = alloc_mbuf(data.len+sizeof(struct phdr))) == NULLBUF){
tprintf(Nospace);
continue;
}
memcpy(bp->data+sizeof(struct phdr),data.buf,data.len);
/* Generate descriptor header */
phdr = (struct phdr *)bp->data;
phdr->iface = pp->iface;
phdr->type = CL_ETHERNET;
bp->cnt = data.len + sizeof(struct phdr);
if (res & MOREDATA)
tprintf("Problems, packet truncated!\n");
enqueue(&Hopper,bp);
}
}
/* Send raw packet (caller provides header) */
int
nit_raw(iface,bp)
struct iface *iface; /* Pointer to interface control block */
struct mbuf *bp; /* Data field */
{
register struct nitdrvr *pp;
struct mbuf *bp1;
struct strbuf proto,data;
struct sockaddr sock;
short size;
pp = &Nitdrvr[iface->dev];
/* pp->stats.xmit++;*/
size = len_p(bp);
if(size < RUNT)
size = RUNT;
if(bp->next != NULLBUF){
/* Copy to contiguous buffer, since driver can't handle mbufs */
bp1 = copy_p(bp,size);
free_p(bp);
bp = bp1;
if(bp == NULLBUF)
return -1;
} else
bp->cnt = size; /* Make sure packet size is big enough */
dump(iface,IF_TRACE_OUT,CL_ETHERNET,bp);
/* Now send the packet to the NIT interface */
sock.sa_family = AF_UNSPEC;
memcpy(sock.sa_data,bp->data,ETHERLEN);
proto.buf = (char *) &sock;
proto.len = sizeof (struct sockaddr);
data.buf = bp->data+ETHERLEN;
data.len = bp->cnt-ETHERLEN;
if (putmsg(pp->IOser,&proto,&data,0) == -1)
perror("putmsg");
free_p(bp);
return 0;
}
int nit_stop()
{}